import celery
import flask
import pagure
import requests
import urllib.parse

from .. import activitypub
from .. import model
from .. import settings
from . import broker
from . import broker_url
from . import database_session

log = celery.utils.log.get_task_logger(__name__)
log.setLevel(settings.LOG_LEVEL)

@broker.task
def handle_incoming_activity(project_id, activity):
    """
    A Tracker has received a new Activity in its INBOX.
    """
    
    with database_session() as (pagure_db, forgefed_graph):
        
        project = pagure_db.query(model.Projects) \
                          .filter(model.Projects.id == project_id) \
                          .one_or_none()
        
        if not project:
            log.info('Actor id(' + project_id + ') doesn\'t exist. Incoming '
                     'Activity will be ignored.')
            return
        
        if activity['type'] == 'Create':
            """
            The Project has received a Create Activity.
            """
            
            # Dereference the actor
            actor = activitypub.fetch(activity['actor'])
            
            # Retrieve the object of the Activity
            object = forgefed_graph.get_json_node(activity['object'])
            
            if object['type'] == 'Note':
                log.debug('Somebody has Created a new Note.')
                
                # We're only interested in Notes that have a "context" property
                # because that contains the URI of the Ticket or MergeRequest
                if 'context' not in object:
                    log.debug('The Note does not contain a "context". Ignoring.')
                    return
                
                model.test_or_set_remote_comment(pagure_db, forgefed_graph, activity['object'])
        
        if activity['type'] == 'Follow':
            """
            Somebody wants to follow this Project.
            """
            
            if activity['object'] != project.local_uri:
                log.info('Actor ' + project.local_uri + ' has received a Follow '
                         'request but the "object" doesn\'t match. '
                         'Activity will be ignored.')
                return
            
            if forgefed_graph.collection_contains(project.followers_uri,
                                                  activity['actor']):
                log.info('Actor ' + project.local_uri + ' is already following '
                         + activity['actor'] + '. Will ignore Follow request.')
                return
            
            # Add the remote object to our followers collection
            forgefed_graph.add_collection_item(project.followers_uri, activity['actor'])
            
            # Commit before accepting the Activity because we want the new
            # follower in the Followers collection before sending out the
            # Accept Activity.
            forgefed_graph.commit()
            
            # Automatically accept Follow requests.
            project.accept(activity['id'])
        
        if activity['type'] == 'Offer':
            """
            Somebody is offering something to the Project, for example a Ticket.
            """
            
            # Retrieve the object of the Offer
            object = forgefed_graph.get_json_node(activity['object'])
            
            if object['type'] == 'Ticket':
                log.debug('Request to create a new Ticket.')
                
                actor = model.test_or_set_remote_actor(pagure_db, forgefed_graph, activity['actor'])
                
                # Create a new local issue in Pagure
                issue = pagure.lib.query.new_issue(
                    pagure_db,
                    project,
                    object['summary'],
                    object['content'],
                    actor.username)
                
                # Send an "Accept" request to notify the remote actor that the
                # ticket was created
                issue_uri = '{}/issue/{}'.format(project.local_uri, issue.id)
                
                project.accept(
                    activity['id'],
                    to=activity['actor'],
                    result=issue_uri)
    
        if activity['type'] == 'Update':
            """
            Somebody has sent us an Update Activity.
            """
            
            # Retrieve the object of the Offer
            object = forgefed_graph.get_json_node(activity['object'])
            
            if object['type'] == 'Ticket':
                log.debug('Request to create a new Ticket.')
                
                actor = model.test_or_set_remote_actor(pagure_db, forgefed_graph, activity['actor'])
                
                # Create a new local issue in Pagure
                issue = pagure.lib.query.new_issue(
                    pagure_db,
                    project,
                    object['summary'],
                    object['content'],
                    actor.username)
                
                # Send an "Accept" request to notify the remote actor that the
                # ticket was created
                issue_uri = '{}/issue/{}'.format(project.local_uri, issue.id)
                
                project.accept(
                    activity['id'],
                    to=activity['actor'],
                    result=issue_uri)
